home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 2: CDPD 1 / Almathera Ten on Ten - Disc 2: CDPD 1.iso / pd / 076-100 / 079 / auxhandler / myaux.c < prev    next >
C/C++ Source or Header  |  1995-03-13  |  14KB  |  558 lines

  1. /****************************************************************************
  2.  *
  3.  *  Aux Driver V1.0 (c)CopyRight 1987, Steve Drew.  All Rights Reserved.
  4.  *  
  5.  *  Aux-Handler Ver. 1.0  1-May-1987
  6.  *
  7.  *  Steve Drew
  8.  *  52-Castledale Cres. N.E.
  9.  *  Calgary, Ab. Canada.
  10.  *
  11.  *  |You may freely distribute this source as long as |
  12.  *  |the Copyright notice is left intact.          |
  13.  ***************************************************************************/
  14.  
  15.  
  16. #include <devices/serial.h>
  17. #include <devices/timer.h>
  18.  
  19.  
  20. typedef unsigned char u_char;
  21.  
  22. #undef  BADDR
  23. #define BADDR(x)   ((APTR)((long)x << 2))
  24.  
  25. #define ACTION_FINDINPUT       1005L
  26. #define ACTION_FINDOUTPUT      1006L
  27. #define ACTION_END           1007L
  28. #define ACTION_SCREEN_MODE     994L
  29.  
  30. #define DOS_FALSE            0L
  31. #define DOS_TRUE                -1L
  32.  
  33. #define AUX_ECHO             1
  34. #define AUX_CRLF             2
  35. #define AUX_RAW              4
  36. #define AUX_RPEND            8
  37. #define AUX_WAIT_FOR         16
  38. #define AUX_TYPEAHEAD_FULL     32
  39. #define AUXBUFSIZE              256  /* Same as CON: handler */
  40. #define MAXLINESIZE           254  /* save two for \n'\0'  */
  41.  
  42.  
  43. #define MYPORT_SIG  (1L << myport->mp_SigBit)
  44. #define READSER_SIG (1L << ReadSER->IOSer.io_Message.mn_ReplyPort->mp_SigBit)
  45. #define TIMER_SIG   (1L << Timer_Port->mp_SigBit)
  46.  
  47. /* extern long AbsExecBase; */
  48.  
  49. /* My Globals */
  50.  
  51.  
  52. struct    IOExtSer    *ReadSER;
  53. struct    IOExtSer    *WriteSER;
  54. struct  timerequest *Timer;
  55. struct    MsgPort     *Timer_Port;
  56. struct  Task          *reader;
  57. long            SysBase;
  58. int            aux_stat, 
  59.             aux_avail,
  60.             in_len;
  61. u_char                in_c;
  62.  
  63. _main()
  64. {
  65.  
  66.     extern void returnpkt();        /* sends back the packet          */
  67.     extern void returnpktplain();    /* use args in Res1               */
  68.     extern struct DosPacket *taskwait();
  69.  
  70.            char       *version =     "Ver 1.0 (c) Steve Drew 1987";
  71.     struct Process    *myproc;         /* my process              */
  72.     struct DosPacket  *mypkt;          /* a pointer to the dos packet    */
  73.     struct DosPacket  *rdpkt;     
  74.     struct DeviceNode *mynode;         /* our device node (parmpkt Arg3) */
  75.     struct FileHandle *fh;         /* a pointer to our file handle      */
  76.     struct MsgPort    *myport;    
  77.     long          run = TRUE;    /* handler main loop flag      */
  78.     u_char            *ptr;        /* ptr for name translation       */
  79.     char          *name,*s;        /* ptr to name for open          */
  80.     int              aux_open = 0;    /* aux open count          */
  81.     char          auxbuf[AUXBUFSIZE];/* Our type ahead buffer      */
  82.     long          signals;        /* signals that occurred in Wait  */
  83.  
  84.  
  85.     /* Initializing the handler */
  86.  
  87.     myproc      = (struct Process *)FindTask(0L);
  88.     mypkt       = taskwait(myproc);      /* Wait for my startup message */
  89.  
  90.     /* I don't need the name or extra info passed in Arg1/2 */
  91.  
  92.     mynode          = (struct DeviceNode *)BADDR(mypkt->dp_Arg3);
  93.     mynode->dn_Task     = &myproc->pr_MsgPort; 
  94.     myport         = &myproc->pr_MsgPort;
  95.     returnpkt(mypkt, myproc, DOS_TRUE, mypkt->dp_Res2); 
  96.  
  97.     in_len = aux_avail = aux_stat = 0;
  98.     reader = (struct Task *) 0;
  99.  
  100.  
  101.     /* done initial stuff, now for some work */
  102.  
  103.     while(run) {
  104.  
  105.     if (aux_open) { /* then wait for read char or new action */
  106.  
  107.         signals = Wait( MYPORT_SIG | READSER_SIG | TIMER_SIG );
  108.  
  109.         if (signals & TIMER_SIG) {
  110.             WaitIO(Timer);
  111.         aux_stat &= ~AUX_WAIT_FOR;
  112.         rdpkt->dp_Res1 = DOS_FALSE;
  113.         returnpktplain(rdpkt,myproc);
  114.         }
  115.         if ((signals & READSER_SIG) && CheckIO(ReadSER)) {
  116.         read_ser(auxbuf);
  117.         chk_pend(auxbuf,rdpkt,myproc);
  118.         }
  119.         if (signals & MYPORT_SIG) {
  120.              mypkt = taskwait(myproc);
  121.         }
  122.         else    /* no new dospackets */
  123.         continue;
  124.     }
  125.     else         /* only port at the moment is myport */
  126.         mypkt = taskwait(myproc);
  127.  
  128.     switch(mypkt->dp_Type) {    /* find what action to perform */
  129.  
  130.     case ACTION_FINDINPUT:
  131.  
  132.         if (reader) {  /* Have I already got a someone reading */
  133.             returnpkt(mypkt, myproc, DOS_FALSE, ERROR_OBJECT_IN_USE);
  134.         break;
  135.         }
  136.  
  137.     case ACTION_FINDOUTPUT:
  138.  
  139.             /*
  140.                 I allow for multiple writers. But doesn't make sense
  141.                 to allow for mutilple readers.
  142.             */
  143.         if (!aux_open)  {  /* first time here we open the devices */
  144.         if ((aux_open = open_stuff()) == 0) {
  145.             returnpkt(mypkt, myproc, DOS_FALSE, ERROR_OBJECT_IN_USE);
  146.             break;
  147.         }
  148.         }
  149.         else
  150.         aux_open++;
  151.  
  152.         /* get file name and Upper case it */
  153.         ptr = (u_char *)BADDR(mypkt->dp_Arg3);
  154.         name = AllocMem((long)*ptr + 1, MEMF_PUBLIC);
  155.         movmem(ptr+1, name, *ptr);
  156.         name[*ptr] = '\0';
  157.         for (s = name; *s; ++s) *s = toupper(*s);
  158.  
  159.     
  160.         /*
  161.         This is a Hack to allow a bail out of a NEWCLI
  162.         that is using the AUX. By doing say an echo >AUX:ENDCLI
  163.         from another process the reader (being the NEWCLI) 
  164.         will be sent a ENDCLI command.
  165.         */
  166.  
  167.         if (!strcmp(name,"AUX:ENDCLI") && (aux_stat & AUX_RPEND)) {
  168.         strcpy(rdpkt->dp_Arg2,"ENDCLI\n");
  169.         rdpkt->dp_Res1 = 7L;
  170.         returnpktplain(rdpkt, myproc);
  171.         aux_stat &= ~AUX_RPEND;
  172.         }
  173.         else
  174.             chk_params(name);
  175.  
  176.         FreeMem(name, (long)*ptr +1);
  177.         fh = (struct FileHandle  *)BADDR(mypkt->dp_Arg1);
  178.         fh->fh_Arg1 = DOS_TRUE;
  179.         fh->fh_Port = (struct MsgPort *)DOS_TRUE;
  180.  
  181.         if (!reader && (mypkt->dp_Type == ACTION_FINDINPUT)) {
  182.             struct MsgPort *port;
  183.             
  184.             port = mypkt->dp_Port;
  185.             reader = port->mp_SigTask;
  186.             fh->fh_Arg1 = (long)port->mp_SigTask;
  187.         }
  188.  
  189.         returnpkt(mypkt, myproc, DOS_TRUE, mypkt->dp_Res2);
  190.         break;
  191.  
  192.     case ACTION_READ:
  193.  
  194.           rdpkt = mypkt;
  195.         aux_stat |= AUX_RPEND;
  196.         chk_pend(auxbuf,rdpkt,myproc);
  197.  
  198.         break;
  199.  
  200.     case ACTION_WRITE:
  201.         
  202.         write_ser(mypkt->dp_Arg2,(int)mypkt->dp_Arg3);
  203.         mypkt->dp_Res1 = mypkt->dp_Arg3;  /* tell em we wrote them all */
  204.  
  205.         returnpktplain(mypkt, myproc);
  206.         break;
  207.  
  208.     case ACTION_WAIT_CHAR:
  209.  
  210.         /* just queue up to wait for data */
  211.  
  212.         rdpkt = mypkt;
  213.         aux_stat |= AUX_WAIT_FOR;
  214.         Timer->tr_time.tv_secs  = 0L;
  215.         Timer->tr_time.tv_micro = rdpkt->dp_Arg1;
  216.         SendIO(Timer);
  217.         chk_pend(auxbuf,rdpkt,myproc);
  218.         break;
  219.         
  220.         case ACTION_SCREEN_MODE:
  221.         
  222.             if (mypkt->dp_Arg1) {
  223.                 aux_stat |= AUX_RAW;
  224.                 aux_stat &= ~AUX_ECHO;
  225.             }
  226.             else {
  227.                 aux_stat &= ~AUX_RAW;
  228.                 aux_stat |= AUX_ECHO;
  229.             }
  230.             chk_pend();
  231.         returnpkt(mypkt, myproc, DOS_TRUE, mypkt->dp_Res2);
  232.             break;
  233.            
  234.     case ACTION_END:
  235.  
  236.         if (--aux_open == 0) {
  237.         run = 0;
  238.         close_timer();
  239.         close_ser();
  240.         }
  241.         if (mypkt->dp_Arg1 == (long)reader) reader = (struct Task *) 0;
  242.         returnpkt(mypkt, myproc, DOS_TRUE, mypkt->dp_Res2);
  243.         break;
  244.  
  245.     default:
  246.  
  247.         returnpkt(mypkt, myproc, DOS_FALSE, ERROR_ACTION_NOT_KNOWN);
  248.         break;
  249.     }
  250.     } /* end while */
  251.     mynode->dn_Task = FALSE; 
  252. }
  253.  
  254.  
  255. /*
  256.     Allows some flexibilty to control the port.
  257.     Can dynamically change CRLF translation,
  258.     Echo or RAW mode on/off.
  259. */
  260. chk_params(str)
  261. char *str;
  262. {
  263.     char *ptr, *s;
  264.     int param, i=1;
  265.     
  266.     if (strncmp(str,"AUX:SET/",8)) return;
  267.     ptr = str + 8;
  268.     while(i) {
  269.     for (s = ptr; *ptr && *ptr != '/'; ++ptr);
  270.     if (*ptr == '\0') i = 0;
  271.     *ptr = '\0';
  272.     str = s+2;
  273.      if (ptr > str) {
  274.         switch (*s) {
  275.         case 'E':
  276.         param = AUX_ECHO;
  277.         break;
  278.         case 'C':
  279.         param = AUX_CRLF;
  280.         break;
  281.         case 'R':
  282.         param = AUX_RAW;
  283.         break;
  284.         default:
  285.             param = 0;
  286.         break;     
  287.         }
  288.                if (*str == 'O') {
  289.         if (*(str+1) == 'N')  aux_stat |= param; 
  290.         else 
  291.             if (*(str+1) == 'F') aux_stat &= ~param;
  292.         }
  293.     }
  294.     ++ptr;
  295.     }
  296. }
  297.  
  298.  
  299. /*
  300.   Start a asynchronous Read request
  301. */
  302. set_read()
  303. {
  304.         /* set up for a read */
  305.     ReadSER->IOSer.io_Length  = 1L;
  306.     ReadSER->IOSer.io_Command = CMD_READ;
  307.     ReadSER->IOSer.io_Data    = (APTR) &in_c;
  308.     SendIO(ReadSER);
  309. }
  310.  
  311. /*
  312.   Check our buf to see if we have a line to return yet. Or if raw mode
  313.   give 'em all we got.
  314. */
  315. chk_pend(buf,pkt,proc)
  316. char         *buf;
  317. struct DosPacket *pkt;
  318. struct Process   *proc;
  319. {
  320.     extern void returnpktplain();
  321.     char *p;
  322.     int i=0;
  323.     
  324.     if ((in_len && (aux_stat & AUX_RAW)) || aux_avail) {
  325.     if (aux_stat & AUX_WAIT_FOR) {
  326.         aux_stat &= ~AUX_WAIT_FOR;      /* clear the wait_for */
  327.         pkt->dp_Res1 = DOS_TRUE;
  328.         AbortIO(Timer);
  329.         WaitIO(Timer);
  330.         Wait (1L << Timer_Port->mp_SigBit);
  331.         returnpktplain(pkt,proc);
  332.     }
  333.     else if (aux_stat & AUX_RPEND) {
  334.         aux_stat &= ~AUX_RPEND;     /* clear the pending read  */
  335.         if (aux_stat & AUX_RAW) { 
  336.         aux_avail = 0;         /* since we're sending all */
  337.         }
  338.         else 
  339.         --aux_avail;
  340.  
  341.         /* if in_len is zero, then aux_avail must of been
  342.            set up to force us here to reply with Res1 = 0;
  343.            thus actually returning an EOF.
  344.         */
  345.         if (in_len) {        
  346.                 for (i = 1,p = (char *) pkt->dp_Arg2; 
  347.                     ((p[i-1] = buf[i-1]) != 10 || (aux_stat & AUX_RAW)) &&
  348.                      i < pkt->dp_Arg3 && i < in_len; ++i) ;
  349.  
  350.         /* reader asked for less than 256 chars but no cr
  351.            was found. If not in raw mode then bump avail back
  352.            up since we still have the remaining CR terminated 
  353.            line in buf[].
  354.         */   
  355.          if (p[i-1] != 10 && !(aux_stat & AUX_RAW)) {
  356.              ++aux_avail;
  357.              }
  358.         }   
  359.         in_len -= i;
  360.         movmem(buf+i,buf,in_len);
  361.         if (in_len < MAXLINESIZE - 1 && (aux_stat & AUX_TYPEAHEAD_FULL)) {
  362.         aux_stat &= ~AUX_TYPEAHEAD_FULL;
  363.         set_read();    /* start waiting for reads again */
  364.         }
  365.         pkt->dp_Res1 = (long)i;
  366.         returnpktplain(pkt,proc);
  367.     }
  368.     }
  369. }
  370.  
  371. /*
  372.   Only called here if there really is a character waiting to be read.
  373. */
  374. read_ser(buf)
  375. char *buf;
  376. {
  377.     char c;    
  378.  
  379.     WaitIO(ReadSER);
  380.     c = in_c;
  381.  
  382.     if (c == 3) {       /* ^C typed so immediately send the signal */
  383.         if (!(aux_stat & AUX_RAW))
  384.         c = 0;
  385.         if (reader)
  386.             Signal(reader,SIGBREAKF_CTRL_C);
  387.     }
  388.  
  389.     if (!(aux_stat & AUX_RAW)) switch(c) {
  390.     case  4:        /* ^D, send the signal if not in raw mode */
  391.     c = 0;
  392.     if (reader)
  393.         Signal(reader,SIGBREAKF_CTRL_D);
  394.     break;
  395.     case 28:        /* ^\ so wipe out line and force EOF      */
  396.     in_len = c = 0;
  397.     ++aux_avail;
  398.     break;
  399.     case 13:        /* CR convert to LF if CRLF turned on      */
  400.     if (aux_stat & AUX_CRLF) c = 10;
  401.     break;
  402.     case 10:        /* ignore these */
  403.         if (aux_stat & AUX_CRLF) c = 0;
  404.         break;
  405.     case 8:        /* BS */
  406.     case 127:        /* DEL */
  407.     if (in_len && buf[in_len-1] != 10) {
  408.         --in_len;
  409.         write_ser("\010 \010",3);
  410.     }
  411.     c = 0;
  412.     break;
  413.     case 24:         /* ^X */
  414.     case 21:        /* ^U */
  415.     while(in_len && buf[in_len-1] != 10) {
  416.         --in_len;        
  417.         write_ser("\010 \010",3);
  418.     }
  419.     c = 0;
  420.     break;
  421.     case 27:        /* <ESC> */
  422.     c = 0;
  423.     default:
  424.     break;
  425.     }
  426.     if (aux_stat & AUX_ECHO) {
  427.     if ((aux_stat & AUX_CRLF) && c == 10) putc_ser(13);
  428.     putc_ser(c);
  429.     }
  430.     if (c == 10)  ++aux_avail;  /* always done when CR received */
  431.        
  432.        /* If our buffer is full then ignore any further input. (it 
  433.           will stack up in the serial.device buffer) If our buffer
  434.           contains no CR's (unterminated) then add a newline. At
  435.           this point the CON: driver would wait for the user to type
  436.           a return while ignoring any other key strokes.
  437.           In raw mode the buffer CAN be full and unterminated. Since
  438.           when ever the reader asks for data we give him what ever
  439.           we have so far.
  440.        */   
  441.     if (in_len >= MAXLINESIZE) {
  442.     aux_stat |= AUX_TYPEAHEAD_FULL;
  443.     if (!aux_avail && !(aux_stat & AUX_RAW)) { 
  444.         ++aux_avail;
  445.         buf[in_len++] = 10;  
  446.     }
  447.     }
  448.     else
  449.         set_read();
  450.  
  451.     if (c) buf[in_len++] = c;
  452. }
  453.  
  454. /*
  455.   Write 'em out one by one converting to CR LF if enabled.
  456. */
  457. write_ser(buf,len)
  458. char *buf;
  459. int len;
  460. {    
  461.     int i=0;
  462.     char c;
  463.     
  464.     for (i=0; i<len; i++) {
  465.     c = buf[i];
  466.     if (c == 10 && (aux_stat & AUX_CRLF)) putc_ser(13);
  467.     putc_ser(c);
  468.     }
  469. }
  470.  
  471. /*
  472.   Perform Synchronous write.
  473. */
  474. putc_ser(c)
  475. char c;
  476. {
  477.     if (c) {
  478.     WriteSER->IOSer.io_Length = 1L;
  479.     WriteSER->IOSer.io_Data = (APTR) &c;
  480.     DoIO(WriteSER);
  481.     }
  482. }
  483.  
  484. open_stuff()
  485. {
  486. BYTE *c,*b;
  487. int i;
  488.  
  489.     aux_stat = AUX_ECHO | AUX_CRLF;  /* set the default */
  490.     if ((ReadSER = (struct IOExtSer *)
  491.       AllocMem((long)sizeof(*ReadSER),MEMF_PUBLIC|MEMF_CLEAR)) == NULL)
  492.     return(0);
  493.     if ((WriteSER = (struct IOExtSer *)
  494.       AllocMem((long)sizeof(*WriteSER),MEMF_PUBLIC|MEMF_CLEAR)) == NULL) {
  495.         FreeMem(ReadSER,(long)sizeof(*ReadSER));
  496.         return(0);
  497.     }          
  498.     ReadSER->IOSer.io_Message.mn_ReplyPort = CreatePort(0,0);
  499.     if (OpenDevice(SERIALNAME,NULL,ReadSER,NULL)) {
  500.     DeletePort(ReadSER->IOSer.io_Message.mn_ReplyPort);
  501.         FreeMem(WriteSER,(long)sizeof(*WriteSER));
  502.     FreeMem(ReadSER,(long)sizeof(*ReadSER));
  503.     return(0);
  504.     }
  505.     
  506.     b = (BYTE *)ReadSER;
  507.     c = (BYTE *)WriteSER;
  508.     for (i=0;i<sizeof(struct IOExtSer);i++) *c++ = *b++;
  509.  
  510.     WriteSER->IOSer.io_Message.mn_ReplyPort = CreatePort(0,0);
  511.     WriteSER->IOSer.io_Command = CMD_WRITE;
  512.  
  513.     /* Open Timer.device */
  514.     if (Timer_Port = CreatePort (NULL, NULL)) {
  515.         if ((Timer = CreateExtIO (Timer_Port, (long) sizeof (*Timer)))) {
  516.             if (!(OpenDevice (TIMERNAME, UNIT_VBLANK, Timer, 0L))) {
  517.                 Timer->tr_node.io_Command = TR_ADDREQUEST;
  518.                 Timer->tr_node.io_Flags = 0;
  519.                 Timer->tr_node.io_Error = 0;
  520.                 set_read();
  521.                 return(1);
  522.             }
  523.         }
  524.     }
  525.     Timer->tr_node.io_Device = 0;
  526.     close_timer();
  527.     close_ser();
  528.     return(0);
  529.  
  530. }
  531.  
  532. close_ser()
  533. {
  534.     if (!(aux_stat & AUX_TYPEAHEAD_FULL)) {
  535.     AbortIO(ReadSER);
  536.     WaitIO(ReadSER);
  537.     }
  538.     DeletePort(WriteSER->IOSer.io_Message.mn_ReplyPort);
  539.     FreeMem(WriteSER,(long)sizeof(*WriteSER));
  540.     CloseDevice(ReadSER);
  541.     DeletePort(ReadSER->IOSer.io_Message.mn_ReplyPort);
  542.     FreeMem(ReadSER,(long)sizeof(*ReadSER));
  543. }
  544.  
  545. close_timer()
  546. {
  547.  
  548.     if (Timer) {
  549.         if (Timer->tr_node.io_Device)
  550.         CloseDevice (Timer);
  551.     DeleteExtIO (Timer, (long) sizeof (*Timer));
  552.     }
  553.     if (Timer_Port)  DeletePort(Timer_Port);
  554.  
  555. }
  556.  
  557.  
  558.